package com.atguigu.demojuc.chap05;

import java.util.Random;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
/*
面试：CyclicBarrier和CountDownLatch的区别？

CountDownLatch允许一个或多个线程等待一组事件的产生，而CyclicBarrier用于等待其他线程运行到栅栏位置
CountDownLatch的计数器只能使用一次，而CyclicBarrier的计数器可以使用多次
所以CyclicBarrier能够处理更为复杂的场景
 */
public class CyclicBarrierDemo {

    /**
     * 组队打boss过关卡游戏
     * 共计三个线程（玩家），要求所有线程执行完某一关（到达某个屏障点），才能够继续执行下一关
     */
    public static void main(String[] args) {
        //1.声明循环栅栏对象 p1:线程数量 p2:所有线程到达屏障点后执行业务-由最后一个到达屏障点线程执行
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {
            System.out.println(Thread.currentThread().getName()+"（裁判）,所有玩家都完成该关卡，继续...");
        });

        //2.创建三个线程，业务逻辑，线程间互相等待，全部到达屏障点，才继续
        for (int i = 1; i <= 3; i++) {
            new Thread(() -> {
                try {
                    //2.1 模拟当前线程过游戏所有关卡
                    System.out.println(Thread.currentThread().getName() + "，开始过第1关");
                    TimeUnit.SECONDS.sleep(new Random().nextInt(5));
                    System.out.println(Thread.currentThread().getName() + "，第1关,已过");
                    cyclicBarrier.await();


                    //2.2 如果当前线程先到达屏障点，其他线程还未到达，将当前线程进入阻塞状态，一直到其他所有线程全部到达屏障点
                    System.out.println(Thread.currentThread().getName() + "，开始过第2关");
                    TimeUnit.SECONDS.sleep(new Random().nextInt(5));
                    System.out.println(Thread.currentThread().getName() + "，第2关,已过");
                    cyclicBarrier.await();


                    System.out.println(Thread.currentThread().getName() + "，开始过第3关");
                    TimeUnit.SECONDS.sleep(new Random().nextInt(5));
                    System.out.println(Thread.currentThread().getName() + "，第3关,已过");
                    cyclicBarrier.await();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }, "玩家" + i).start();
        }
    }
}